package com.seven.first.suite.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

public class MyBase64Util {
    //private static final String[] BASE64CHAR = new String[]{"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/","="};
    //private static final String BASE64STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    
    private static HashMap<String,Integer> HASH_STR = new HashMap<String,Integer>();
    private static HashMap<Integer,String> HASH_INT = new HashMap<Integer,String>();
    static{
    	HASH_STR.put("A", 0);
    	HASH_INT.put(0, "A");
    	HASH_STR.put("B", 1);
    	HASH_INT.put(1, "B");
    	HASH_STR.put("C", 2);
    	HASH_INT.put(2, "C");
    	HASH_STR.put("D", 3);
    	HASH_INT.put(3, "D");
    	HASH_STR.put("E", 4);
    	HASH_INT.put(4, "E");
    	HASH_STR.put("F", 5);
    	HASH_INT.put(5, "F");
    	HASH_STR.put("G", 6);
    	HASH_INT.put(6, "G");
    	HASH_STR.put("H", 7);
    	HASH_INT.put(7, "H");
    	HASH_STR.put("I", 8);
    	HASH_INT.put(8, "I");
    	HASH_STR.put("J", 9);
    	HASH_INT.put(9, "J");
    	HASH_STR.put("K", 10);
    	HASH_INT.put(10, "K");
    	HASH_STR.put("L", 11);
    	HASH_INT.put(11, "L");
    	HASH_STR.put("M", 12);
    	HASH_INT.put(12, "M");
    	HASH_STR.put("N", 13);
    	HASH_INT.put(13, "N");
    	HASH_STR.put("O", 14);
    	HASH_INT.put(14, "O");
    	HASH_STR.put("P", 15);
    	HASH_INT.put(15, "P");
    	HASH_STR.put("Q", 16);
    	HASH_INT.put(16, "Q");
    	HASH_STR.put("R", 17);
    	HASH_INT.put(17, "R");
    	HASH_STR.put("S", 18);
    	HASH_INT.put(18, "S");
    	HASH_STR.put("T", 19);
    	HASH_INT.put(19, "T");
    	HASH_STR.put("U", 20);
    	HASH_INT.put(20, "U");
    	HASH_STR.put("V", 21);
    	HASH_INT.put(21, "V");
    	HASH_STR.put("W", 22);
    	HASH_INT.put(22, "W");
    	HASH_STR.put("X", 23);
    	HASH_INT.put(23, "X");
    	HASH_STR.put("Y", 24);
    	HASH_INT.put(24, "Y");
    	HASH_STR.put("Z", 25);
    	HASH_INT.put(25, "Z");
    	HASH_STR.put("a", 26);
    	HASH_INT.put(26, "a");
    	HASH_STR.put("b", 27);
    	HASH_INT.put(27, "b");
    	HASH_STR.put("c", 28);
    	HASH_INT.put(28, "c");
    	HASH_STR.put("d", 29);
    	HASH_INT.put(29, "d");
    	HASH_STR.put("e", 30);
    	HASH_INT.put(30, "e");
    	HASH_STR.put("f", 31);
    	HASH_INT.put(31, "f");
    	HASH_STR.put("g", 32);
    	HASH_INT.put(32, "g");
    	HASH_STR.put("h", 33);
    	HASH_INT.put(33, "h");
    	HASH_STR.put("i", 34);
    	HASH_INT.put(34, "i");
    	HASH_STR.put("j", 35);
    	HASH_INT.put(35, "j");
    	HASH_STR.put("k", 36);
    	HASH_INT.put(36, "k");
    	HASH_STR.put("l", 37);
    	HASH_INT.put(37, "l");
    	HASH_STR.put("m", 38);
    	HASH_INT.put(38, "m");
    	HASH_STR.put("n", 39);
    	HASH_INT.put(39, "n");
    	HASH_STR.put("o", 40);
    	HASH_INT.put(40, "o");
    	HASH_STR.put("p", 41);
    	HASH_INT.put(41, "p");
    	HASH_STR.put("q", 42);
    	HASH_INT.put(42, "q");
    	HASH_STR.put("r", 43);
    	HASH_INT.put(43, "r");
    	HASH_STR.put("s", 44);
    	HASH_INT.put(44, "s");
    	HASH_STR.put("t", 45);
    	HASH_INT.put(45, "t");
    	HASH_STR.put("u", 46);
    	HASH_INT.put(46, "u");
    	HASH_STR.put("v", 47);
    	HASH_INT.put(47, "v");
    	HASH_STR.put("w", 48);
    	HASH_INT.put(48, "w");
    	HASH_STR.put("x", 49);
    	HASH_INT.put(49, "x");
    	HASH_STR.put("y", 50);
    	HASH_INT.put(50, "y");
    	HASH_STR.put("z", 51);
    	HASH_INT.put(51, "z");
    	HASH_STR.put("0", 52);
    	HASH_INT.put(52, "0");
    	HASH_STR.put("1", 53);
    	HASH_INT.put(53, "1");
    	HASH_STR.put("2", 54);
    	HASH_INT.put(54, "2");
    	HASH_STR.put("3", 55);
    	HASH_INT.put(55, "3");
    	HASH_STR.put("4", 56);
    	HASH_INT.put(56, "4");
    	HASH_STR.put("5", 57);
    	HASH_INT.put(57, "5");
    	HASH_STR.put("6", 58);
    	HASH_INT.put(58, "6");
    	HASH_STR.put("7", 59);
    	HASH_INT.put(59, "7");
    	HASH_STR.put("8", 60);
    	HASH_INT.put(60, "8");
    	HASH_STR.put("9", 61);
    	HASH_INT.put(61, "9");
    	HASH_STR.put("+", 62);
    	HASH_INT.put(62, "+");
    	HASH_STR.put("/", 63);
    	HASH_INT.put(63, "/");
    	//HASH_STR.put("=", 64);
    	HASH_INT.put(64, "=");
    }
	 
    public static Optional<String> encodeStr(String bs){
    	try{
    		String r = MyBase64Util.encode(bs.getBytes());
    		return Optional.of(r);
    	}catch(Exception e){
    		return Optional.empty();
    	}
    }
    public static Optional<String> decodeStr(String bs){
    	try{
    		byte[] r = MyBase64Util.decode(bs);
    		return Optional.of(new String(r));
    	}catch(Exception e){
    		return Optional.empty();
    	} 
    }
    
    
	public static String encode(byte[] bs) throws Exception{
		StringBuffer sb = new StringBuffer();
		for(int i=0;i<bs.length;){
			int[] result = new int[]{64,64,64,64};
			if(i<bs.length-2){
				byte b1 = bs[i];
				byte b2 = bs[i+1];
				byte b3 = bs[i+2];
				
				result[0] = (b1 & 0xFC) >> 2;
				result[1] = (((b1 & 0x03) << 4 ) | ((b2 & 0xF0)>>4)) & 0xFF;
				result[2] = (((b2 & 0x0F) << 2) | ((b3 & 0xC0) >> 6)) & 0xFF;
				result[3] = b3 & 0x3F;
			}
			else if(i<bs.length-1){
				byte b1 = bs[i];
				byte b2 = bs[i+1];
				
				result[0] = (b1 & 0xFC) >> 2;
				result[1] = (((b1 & 0x03) << 4 ) | ((b2 & 0xF0)>>4)) & 0xFF;
				result[2] = (((b2 & 0x0F) << 2) ) & 0xFF;
			}
			else if(i<bs.length){
				byte b1 = bs[i];
				
				result[0] = (b1 & 0xFC) >> 2;
				result[1] = (((b1 & 0x03) << 4 )) & 0xFF;
			}
			i += 3;
			sb.append(HASH_INT.get(result[0])+HASH_INT.get(result[1])+HASH_INT.get(result[2])+HASH_INT.get(result[3]));
		}
		return sb.toString();
	}
	
	public static byte[] decode(String str) throws Exception{	
		if(str==null)return null;
		str = str.trim();
		if(str.length()==0)return null;
		int length = str.length();
		List<Integer> list = new ArrayList<Integer>();
		int endFlag = 0;
		for(int i=0;i<length;i++){	
			String s = str.charAt(i)+"";
			if(i>length-3){				
				if(endFlag==0 && s.equals("=")){
					endFlag = length-i;
				}
			}
			if(endFlag>0 && !s.equals("=")){
				throw new Exception("Input String is not a base64 string !!!!!!!!!!!!!!");
			}
			else if(endFlag==0 && !HASH_STR.containsKey(s)){
				throw new Exception("Input String is not a base64 string !!!!!!!!!!!!!!");
			}
			if(endFlag==0)
			    list.add(HASH_STR.get(s));
		}
		//System.out.println(endFlag+"============");
		if(list.size()<=0){
			throw new Exception("Input String is not a base64 string !!!!!!!!!!!!!!");
		}
		List<Byte> result = new ArrayList<Byte>();
		for(int i=0;i<list.size();){
			if(i<=list.size()-4){
				int a1 = list.get(i);
				int a2 = list.get(i+1);
				int a3 = list.get(i+2);
				int a4 = list.get(i+3);
				
				byte b1 = (byte)((((a1 & 0x3F) << 2) | ((a2 & 0x30) >> 4)) & 0xFF);
				byte b2 = (byte)((((a2 & 0x0F) << 4) | ((a3 & 0x3C) >> 2)) & 0xFF);
				byte b3 = (byte)((((a3 & 0x03) << 6) | ((a4 & 0x3F))) & 0xFF);
				
				result.add(b1);
				result.add(b2);
				result.add(b3);
			}
			else{
				if(endFlag==1){
					int a1 = list.get(i);
					int a2 = list.get(i+1);
					int a3 = list.get(i+2);
					
					byte b1 = (byte)((((a1 & 0x3F) << 2) | ((a2 & 0x30) >> 4)) & 0xFF);
					byte b2 = (byte)((((a2 & 0x0F) << 4) | ((a3 & 0x3C) >> 2)) & 0xFF);
					
					result.add(b1);
					result.add(b2);
				}
				else if(endFlag==2){
					int a1 = list.get(i);
					int a2 = list.get(i+1);
					
					byte b1 = (byte)((((a1 & 0x3F) << 2) | ((a2 & 0x30) >> 4)) & 0xFF);
					
					result.add(b1);
				}
			}
			i = i+4;
		}
		byte[] bs = new byte[result.size()];
		for(int i=0;i<result.size();i++){
			bs[i] = (byte)result.get(i);
		}
		return bs;
	}
	
	
	
	public static void main(String[] args) throws Exception{
		String str = "3月20日前完成参观接待展示的系统视频，于婷协助刘处准备讲词，离退部提前确认，录1=";
//		sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
//		
//		sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
//		System.out.println(encoder.encode(str.getBytes("UTF-8")));
		String s = encode(str.getBytes("UTF-8"));
//		s="amFzeXB0LmVuY3J5cHRvci5wYXNzd29yZA==";
		System.out.println(s);
		byte[] bs = decode(s);
		System.out.println(new String(bs,"UTF-8"));
		//System.out.println(new String(decoder.decodeBuffer(s),"UTF-8"));
		//System.out.println((byte)234);
		
		

	}
}
